import { PlusOutlined } from "@ant-design/icons";
import { getBaseUrl, getToken } from "@/utils/request";
import { GetProp, UploadProps, UploadFile, message, Upload, Image, Form, FormItemProps } from "antd";
import { useState, useRef, useEffect } from "react";

type FileType = Parameters<GetProp<UploadProps, "beforeUpload">>[0];

export const UploadImg = (props?: FormItemProps) => {
    const { id = "avatar" } = props || {};
    const getBase64 = (file: FileType): Promise<string> =>
        new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result as string);
            reader.onerror = error => reject(error);
        });
    const [fileList, setFileList] = useState<UploadFile[]>([]);
    const [previewOpen, setPreviewOpen] = useState(false);
    const [previewImage, setPreviewImage] = useState("");
    const canUpload = useRef(false);
    const handlePreview = async (file: UploadFile) => {
        if (!file.url && !file.preview) {
            file.preview = await getBase64(file.originFileObj as FileType);
        }
        setPreviewImage(file.url || (file.preview as string));
        setPreviewOpen(true);
    };

    const handleChange: UploadProps["onChange"] = ({ file, fileList }) => {
        if (!canUpload.current) return;
        const url = file.response?.data?.url;
        let list = fileList;
        if (url) {
            list = fileList.map(item => ({ ...item, url }));
        }
        setFileList(list);
    };

    const uploadButton = (
        <button style={{ border: 0, background: "none" }} type="button">
            <PlusOutlined />
            <div style={{ marginTop: 8 }}>上传</div>
        </button>
    );
    const beforeUpload = (file: FileType) => {
        const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
        if (!isJpgOrPng) {
            message.error("只允许上传JPG/PNG文件!");
        }
        const isLt5M = file.size / 1024 / 1024 < 5;
        if (!isLt5M) {
            message.error("最大允许上传5MB的文件!");
        }
        canUpload.current = isJpgOrPng && isLt5M;
        return canUpload.current;
    };

    const isRemove = useRef(false);
    const handleRemove = () => {
        isRemove.current = true;
        setFileList([]);
    };
    const preAvaiableUrl = useRef<null | string>(null);
    return (
        <div style={{ height: "102px" }}>
            <Form.Item
                name={id}
                shouldUpdate={(_, val: Record<string, any>) => {
                    if (val[id] && val[id] !== preAvaiableUrl.current) {
                        setFileList([{ url: val[id], uid: Date.now().toString(), name: "init" }]);
                        preAvaiableUrl.current = val[id];
                    }
                    return true;
                }}
                getValueFromEvent={val => {
                    if (isRemove.current) {
                        isRemove.current = false;
                        return null;
                    }
                    const { file } = val;
                    const url = file?.response?.data.url;
                    if (url) preAvaiableUrl.current = url;
                    return url || preAvaiableUrl.current || null;
                }}
            >
                <Upload
                    maxCount={1}
                    accept="image/png,image/jpeg"
                    action={`${getBaseUrl()}/file/upload`}
                    headers={{ Authorization: getToken() }}
                    listType="picture-circle"
                    fileList={fileList}
                    onPreview={handlePreview}
                    onRemove={handleRemove}
                    beforeUpload={beforeUpload}
                    onChange={handleChange}
                >
                    {uploadButton}
                </Upload>
            </Form.Item>
            {previewImage && (
                <Image
                    wrapperStyle={{ display: "none" }}
                    preview={{
                        visible: previewOpen,
                        onVisibleChange: visible => setPreviewOpen(visible),
                        afterOpenChange: visible => !visible && setPreviewImage(""),
                    }}
                    src={previewImage}
                />
            )}
        </div>
    );
};
